<script setup lang="ts">
import { onMounted, ref } from "vue"

const canvasEl = ref(null), hText = ref(null)

enum DemoType {
  POINT = 'point',
  DRAG = 'drag',
  COLOR = 'color',
}
const props = defineProps({
  demoName: {
    type: String,
    validator(value: string): boolean {
      return [DemoType.POINT, DemoType.DRAG, DemoType.COLOR].includes(value)
    },
    default: DemoType.POINT
  }
})

const isInPoint = () => {
  const ctx = canvasEl.value.getContext('2d')

  const getRandom = (a = 0, b = 600) => {
    return Math.random() * (b - a) + a
  }

  const checkPoint = (point, lines) => {
    let intersectionCount = 0
    let { x, y } = point
    for (const line of lines) {
      let { p1, p2 } = line
      if((p1.y < y && p2.y < y) || (p1.y >= y && p2.y >= y)) {}
      else {
        // 交点
        const sx = ((y - p1.y) / (p2.y - p1.y)) * (p2.x - p1.x) + p1.x
        if (sx >= x) {
          intersectionCount++
        }
      }

    }
    return intersectionCount % 2 === 0
  }

  ctx.fillStyle = 'blue'
  // n边形
  const vertexNum = 5
  // 顶点
  let vertexArr = []
  // lines
  const lineArr = []
  for (const vertexNumElement of Array.from({ length: vertexNum })) {
    vertexArr.push({ x: getRandom(), y: getRandom() })
  }

  ctx.beginPath()
  vertexArr.forEach((item, index) => {
    let preV
    if(index === 0) {
      ctx.moveTo(item.x, item.y)
      preV = vertexArr.at(-1)
    }else {
      ctx.lineTo(item.x, item.y)
      preV = vertexArr.at(index - 1)
    }
    lineArr.push({ p1: preV, p2: item })
  })

  ctx.closePath()
  ctx.fill()

  canvasEl.value.addEventListener('mousemove', (e) => {
    const { offsetX: x, offsetY: y } = e
    const isOutside = checkPoint({ x, y }, lineArr)
    hText.value.innerText = `图形${isOutside ? '外' : '内'}`
  })
}

const simpleDrag = () => {
  const ctx = canvasEl.value.getContext('2d')

  const controlSize = 20 // 控制块大小
  let isMoveControl = false // 拖拽开启标志
  let curTransform = null // 上一次拖拽记录

  function drawRect(ctx, rect) {
    ctx.clearRect(0, 0, canvasEl.value.width, canvasEl.value.height)
    rect.NewcontrolRect = getNewControlRect(rect)
    let { x, y, w, h, scaleX, scaleY } = rect
    ctx.save()
    ctx.translate(x, y)
    ctx.scale(scaleX, scaleY)
    // 绘制矩形
    ctx.beginPath()
    ctx.fillStyle = 'green'
    ctx.fillRect(0, 0, w, h)
    ctx.save()
    ctx.scale(1 / scaleX, 1 / scaleY)
    // 绘制矩形原原点
    ctx.beginPath()
    ctx.fillStyle = 'black'
    ctx.arc(0, 0, 10, 0, 2 * Math.PI)
    ctx.fill()
    // 绘制左边中间控制点
    ctx.beginPath()
    ctx.fillStyle = 'red'
    ctx.fillRect(w * scaleX - controlSize / 2, h / 2 - controlSize / 2, controlSize, controlSize)
    // 绘制右边中间控制点
    ctx.beginPath()
    ctx.fillStyle = 'blue'
    ctx.fillRect(-controlSize / 2, h / 2 - controlSize / 2, controlSize, controlSize)
    ctx.restore()
    ctx.restore()
  }
  function pointInControl(point, rect) {

    let obj = null, position = ''
    const realWidth = rect.scaleX * rect.x
    if(point.x - rect.x <= 20) {
      obj = rect.NewcontrolRect.leftC
      position = 'right'
    }
    if(point.x - rect.x > 50) {
      obj = rect.NewcontrolRect.rightC
      position = 'left'
    }
    if(!obj) return false
    const { x, y, w, h } = obj

    const { x: pointX, y: pointY } = point
    if(pointX >= x && pointX <= x + w && pointY >= y && pointY <= y + h) {
      return position
    }
    return false
  }

  function getNewControlRect(rect) {
    let { x, y, w, h, scaleX, scaleY } = rect
    let leftC = {
      x: x - controlSize / 2,
      y: y + h / 2 - controlSize / 2,
      w: controlSize,
      h: controlSize
    }
    let rightC = {
      x: x + w * scaleX - controlSize / 2,
      y: y + h / 2 - controlSize / 2,
      w: controlSize,
      h: controlSize,
    }
    return { leftC, rightC }
  }

  const rect = {
    x: 300,
    y: 100,
    w: 200,
    h: 200,
    scaleX: 1,
    scaleY: 1,
  }
  drawRect(ctx, rect)

  document.addEventListener('mousemove', (e) => {
    e.preventDefault()
    const point = {
      x: e.offsetX,
      y: e.offsetY,
    }
    if (isMoveControl) {
      rect.scaleX = calcNewScaleX(curTransform, point)
      drawRect(ctx, rect)
    } else {
      const isInControl = pointInControl(point, rect)
      if (isInControl) {
        canvasEl.value.style.cursor = 'e-resize'
      } else {
        canvasEl.value.style.cursor = ''
      }
    }
  })

  canvasEl.value.addEventListener('mousedown', (e) => {
    e.preventDefault()
    const point = {
      x: e.offsetX,
      y: e.offsetY,
    }
    const isInControl = pointInControl(point, rect)
    if (!isInControl) return
    isMoveControl = true
    curTransform = {
      ex: point.x,
      ey: point.y,
      x: rect.x,
      y: rect.y,
      w: rect.w * rect.scaleX,
      h: rect.h * rect.scaleY,
      scaleX: rect.scaleX,
      originX: isInControl,
      originY: 'center',
    }
  })
  document.addEventListener('mouseup', (e) => {
    e.preventDefault()
    isMoveControl = false
    curTransform = null
  })

  function calcNewScaleX(curTransform, point) {
    const { ex, ey, x, y } = curTransform
    const { w } = rect
    const { x: pointX, y: pointY } = point
    let scale = 1
    if (curTransform.originX === 'left') {
      scale = (pointX - x) / w
      rect.x = curTransform.x
    } else if (curTransform.originX === 'right') {
      const { scaleX: oldScaleX } = curTransform
      scale = (w * oldScaleX + (x - pointX)) / w
      const dx = x - pointX
      rect.x = pointX
    }
    return scale
  }
}

const colorInPoint = () => {
  const ctx = canvasEl.value.getContext('2d')

  const canvasEl2 = document.querySelector('#canvasColor')
  const ctx2 = canvasEl2.getContext('2d')

  function drawFive(ctxContext, color, useFill = false) {
    ctxContext.save()
    ctxContext.beginPath()
    if(useFill) {
      ctxContext.fillStyle = color
      ctxContext.fill()
    }else {
      ctxContext.strokeStyle = color
    }

    for (let i = 0; i < 5; i++) {
      ctxContext.lineTo(Math.cos((18+i*72)/180*Math.PI)*200+200,
          -Math.sin((18+i*72)/180*Math.PI)*200+200)
      ctxContext.lineTo(Math.cos((54+i*72)/180*Math.PI)*80+200,
          -Math.sin((54+i*72)/180*Math.PI)*80+200)
    }
    ctxContext.closePath()
    if(useFill) {
      ctxContext.fill()
    }else {
      ctxContext.stroke()
    }

    ctxContext.restore()
  }
  drawFive(ctx, 'blue', true)
  drawFive(ctx2, 'red', true)

  canvasEl.value.onmousedown = (e) => {
    const pix = ctx2.getImageData(e.offsetX, e.offsetY, 1, 1)
    const data = pix.data
    const rgba = `rgba(${data[0]}, ${data[1]}, ${data[2]}, ${data[3] / 255})`
    hText.value.innerText = rgba
  }
}

onMounted(() => {
  switch (props.demoName) {
    case DemoType.POINT:
      isInPoint()
      break
    case DemoType.DRAG:
      simpleDrag()
      break
    case DemoType.COLOR:
      colorInPoint()
      break
  }
})

</script>

<template>
  <div v-if="props.demoName === DemoType.POINT">
    <canvas
        ref="canvasEl"
        width="600"
        height="600"
        class="canvas">
    </canvas>
    <h3 ref="hText" style="color: red"></h3>
  </div>
  <div v-else-if="props.demoName === DemoType.DRAG">
    <canvas
        ref="canvasEl"
        width="600"
        height="600"
        class="canvas">
    </canvas>
  </div>
  <div v-else-if="props.demoName === DemoType.COLOR" class="relative" style="height: 400px; width: 600px">
    <canvas
        ref="canvasEl"
        width="600"
        height="400"
        class="canvas absolute left-0 top-0 w-full">
    </canvas>
    <canvas
        id="canvasColor"
        width="600"
        height="400"
        class="canvas invisible">
    </canvas>
    <h3 ref="hText" class="absolute left-0 bottom-0"></h3>
  </div>
</template>

<style scoped lang="scss">
.canvas {
  border: 1px solid lightpink;
}
</style>